﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using NLite.Collections;
using NLite.Mini.Context;
using NLite.Reflection;
using NLite.Mini.Activation;
using NLite.Mini.Listener;

namespace NLite.Internal
{
    class ReflectionHelper
    {
       
        public static object[] GetParameters(Type type, ConstructorInfo constructor, IKernel kernel)
        {
            var ps = constructor.GetParameters();
            return GetParameters(kernel, ps);
        }

        public static object[] GetParameters(IKernel kernel, ParameterInfo[] ps)
        {
            int length = ps.Length;
            object[] result = new object[length];
            foreach (var p in ps)
            {
                var att = p.GetAttribute<InjectAttribute>(false);
                var id = att != null ? att.Id : string.Empty;
                var parameterType = p.ParameterType;

                result[p.Position] = InjectService.Get(id, parameterType, kernel, p.HasAttribute<InjectManyAttribute>(false));
            }
            return result;
        }

        public static ConstructorInfo FindEligibleConstructor(Type typeToConstruct, IKernel kernel)
        {
            var methods = (from c in typeToConstruct.GetConstructors()
                           let ps = c.GetParameters()
                           where ps.TrueForAll(p => MemberMatcher.Match(p,kernel))
                           orderby ps.Length descending
                           select c).ToArray();

            var result = (from m in methods
                          let attr = m.GetAttribute<InjectAttribute>(true)
                          where attr != null
                          select m).FirstOrDefault();
            if (result != null)
                return result;

            var constructor = methods.FirstOrDefault();

            if (constructor == null && !typeToConstruct.IsValueType)
                throw new ActivatorException("Could not find eligible constructor for " + typeToConstruct.FullName);
            return constructor;
        }
    }
}
